package l1j.server.server.model;

import static l1j.server.server.model.skill.L1SkillId.*;

import java.util.logging.Level;
import java.util.logging.Logger;

import l1j.opqlo.NewSystem.L1AttackCancel;
import l1j.opqlo.NewSystem.Attack.L1AttackList;
import l1j.opqlo.Timer.Controler.Server.ServerWarExecutor;
import l1j.server.Config;
import l1j.server.server.ActionCodes;
import l1j.server.server.datatables.SkillsTable;
import l1j.server.server.model.Instance.L1NpcInstance;
import l1j.server.server.model.Instance.L1PcInstance;
import l1j.server.server.model.Instance.L1PetInstance;
import l1j.server.server.model.Instance.L1SummonInstance;
import l1j.server.server.serverpackets.S_DoActionGFX;
import l1j.server.server.serverpackets.S_ServerMessage;
import l1j.server.server.serverpackets.S_SkillSound;
import l1j.server.server.templates.L1Skills;
import l1j.server.server.utils.Random;
import static l1j.server.server.model.skill.L1SkillId.蒜頭雞湯;
import static l1j.server.server.model.skill.L1SkillId.烏骨雞湯;


public class L1Magic {
	private int _calcType;

	private final int PC_PC = 1;

	private final int PC_NPC = 2;

	private final int NPC_PC = 3;

	private final int NPC_NPC = 4;

	private L1PcInstance _pc = null;

	private L1PcInstance _targetPc = null;

	private L1NpcInstance _npc = null;

	private L1NpcInstance _targetNpc = null;

	private int _leverage = 10; // 1/10倍で表現する。

	private static final Logger _log = Logger
			.getLogger(L1Magic.class.getName());

	private int magicDmgMod;

	public L1Magic(final L1Character attacker, final L1Character target) {
		try {
			if (attacker instanceof L1PcInstance) {
				if (target instanceof L1PcInstance) {
					this._calcType = this.PC_PC;
					this._pc = (L1PcInstance) attacker;
					this._targetPc = (L1PcInstance) target;
				} else {
					this._calcType = this.PC_NPC;
					this._pc = (L1PcInstance) attacker;
					this._targetNpc = (L1NpcInstance) target;
				}
			} else {
				if (target instanceof L1PcInstance) {
					this._calcType = this.NPC_PC;
					this._npc = (L1NpcInstance) attacker;
					this._targetPc = (L1PcInstance) target;
				} else {
					this._calcType = this.NPC_NPC;
					this._npc = (L1NpcInstance) attacker;
					this._targetNpc = (L1NpcInstance) target;
				}
			}
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}
	}

	// ●●●● ATTR属性傷害減少 ●●●●
	// attr:0.無属性魔法,1.地魔法,2.火魔法,4.水魔法,8.風魔法(,16.光魔法)
	private double calcAttrResistance(final int attr) {
		int resist = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
			if (attr == L1Skills.ATTR_EARTH) {
				resist = this._targetPc.getEarth();
			} else if (attr == L1Skills.ATTR_FIRE) {
				resist = this._targetPc.getFire();
			} else if (attr == L1Skills.ATTR_WATER) {
				resist = this._targetPc.getWater();
			} else if (attr == L1Skills.ATTR_WIND) {
				resist = this._targetPc.getWind();
			}
		} else if (this._calcType == this.PC_NPC
				|| this._calcType == this.NPC_NPC) {
		}

		int resistFloor = (int) (0.32 * Math.abs(resist));
		if (resist >= 0) {
			resistFloor *= 1;
		} else {
			resistFloor *= -1;
		}

		final double attrDeffence = resistFloor / 32.0;

		return attrDeffence;
	}

	/**
	 * 計算恢復系列魔法的恢復值
	 * **/
	public int calcHealing(final int skillId) {
		final L1Skills l1skills = SkillsTable.getInstance().getTemplate(skillId);
		final int dice = l1skills.getDamageDice();
		final int value = l1skills.getDamageValue();
		int magicDamage = 0;

		final int magicBonus = Math.min(this.getMagicBonus(), 10);
//		System.out.println("magicBonus: "+magicBonus);
		final int diceCount = value + magicBonus;
		for (int i = 0; i < diceCount; i++) {
			magicDamage += Random.nextInt(dice) + 1;
		}

		double alignmentRevision = 1.0;
		if (this.getLawful() > 0) {
			alignmentRevision += this.getLawful() / 32768.0;
		}
		magicDamage *= alignmentRevision;
//		System.out.println("Leverage: "+this.getLeverage());
		magicDamage = magicDamage * this.getLeverage() / 10;
//		System.out.println("magicDamage: "+magicDamage);
		return magicDamage;
	}

	public int calcMagicDamage(final int skillId) {
		int damage = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
			damage = Math.max(0, this.calcPcMagicDamage(skillId));
			
			if(this._calcType == this.PC_PC && this._pc!=null && this._pc.hasSkillEffect(蒜頭雞湯)){
				damage *= 1.1;
			}
			if(this._targetPc !=null && this._targetPc.hasSkillEffect(烏骨雞湯)){
				damage *= 0.9;
			}
		} else if (this._calcType == this.PC_NPC
				|| this._calcType == this.NPC_NPC) {
			damage = Math.max(1, this.calcNpcMagicDamage(skillId));
			if(this._calcType == this.PC_NPC && this._pc!=null && this._pc.hasSkillEffect(蒜頭雞湯)){
				damage *= 1.1;
			}
		}
		damage = Math.max(1, this.calcMrDefense(damage));
		return damage;
	}

	// ●●●● damage_dice、damage_dice_count、damage_value、SPから魔法ダメージを算出 ●●●●
	private int calcMagicDiceDamage(final int skillId) {
		final L1Skills l1skills = SkillsTable.getInstance()
				.getTemplate(skillId);
		final int dice = l1skills.getDamageDice();
		final int diceCount = l1skills.getDamageDiceCount();
		final int value = l1skills.getDamageValue();
		int magicDamage = 0;
		int charaIntelligence = 0;
		if (diceCount == 1) {
			magicDamage += Random.nextInt(dice) + 1;
		} else if (diceCount > 1) {
			for (int i = diceCount; i > 0; i--) {
				magicDamage += Random.nextInt(dice) + 1;
			}
		}
		magicDamage += value;

		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
			this.magicDmgMod = this._pc.getMagicDmgModfier();
			if (this._pc.isElf() || this._pc.isDragonKnight()) {
				this.magicDmgMod /= 2;
			} else if (this._pc.isWizard()) {
			} else {
				this.magicDmgMod /= 4;// *2
			}

			if (this.magicDmgMod > 0) {
				// if(_calcType == PC_PC){
				// magicDmgMod -= (_targetPc.getMr());// /2
				// }
				magicDamage += this.magicDmgMod
						+ Random.nextInt(this.magicDmgMod); // opqlo 法術增傷
				// System.out.println("A:"+magicDamage);
			}

			final int spByItem = this._pc.getSp() - this._pc.getTrueSp(); // アイテムによるSP変動
			charaIntelligence = Random.nextInt(this._pc.getInt() + spByItem- 12);

		} else {
			final int spByItem = this._npc.getSp() - this._npc.getTrueSp(); // アイテムによるSP変動
			charaIntelligence = this._npc.getInt() + spByItem - 12;
		}
		charaIntelligence = Math.max(charaIntelligence, 1);

		final double attrDeffence = this.calcAttrResistance(l1skills.getAttr());

		final double coefficient = Math.max(1.0 - attrDeffence+ charaIntelligence * 3.0 / 32.0, 0);

		magicDamage *= coefficient;

		final double criticalCoefficient = 1.5; // 魔法クリティカル
		final int rnd = Random.nextInt(100) + 1;
		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {

			if (l1skills.getSkillLevel() <= 6) {
				if (rnd <= 10 + this._pc.getOriginalMagicCritical()) {
					magicDamage *= criticalCoefficient;
				}
			}
			// オリジナルINTによる魔法ダメージ
			magicDamage += this._pc.getOriginalMagicDamage();
			if (this._pc.hasSkillEffect(ILLUSION_AVATAR)) {// アバターによる追加ダメージ
				magicDamage += 10;
			}
		}
		// System.out.println("B:"+magicDamage);

		return magicDamage;
	}

	// ●●●● MR魔法傷害減少●●●●
	private int calcMrDefense(int dmg) {
		final int mr = this.getTargetMr();

		double mrFloor = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {

			double mrCoefficient = 0;
			final Double[] mrF = L1AttackList.MRDMG.get(new Integer(mr));

			if (mrF != null) {
				mrFloor = mrF[0].doubleValue();
				mrCoefficient = mrF[1].doubleValue();

			} else {
				mrFloor = 16.5;
				mrCoefficient = 0.71;
			}
			// 計算減低的傷害
//			System.out.println("mr:"+mr);
//			System.out.println("magicDmgMod:"+this.magicDmgMod/2 );
//			System.out.println("OriginalMagicHit:"+this._pc.getOriginalMagicHit());
//			System.out.println("mrFloor:"+mrFloor);
//			System.out.println("mrCoefficient:"+mrCoefficient);
			final double rate = 0.01 * Math.floor((mr -(this.magicDmgMod/2 )-this._pc.getOriginalMagicHit()) / mrFloor);
//			System.out.println("rate:"+rate);
//			System.out.println("srcDMG:"+dmg);
			dmg *= mrCoefficient - rate;
//			System.out.println("DMG:"+dmg);
			if (dmg <= 0) {
				return 0;
			}
			// System.out.println("mrCoefficient:"+ mrCoefficient+
			// " / Math.floor:"+Math.floor(( mr - ((magicDmgMod
			// /2)+_pc.getOriginalMagicHit())) / mrFloor));
			// System.out.println("magicDmgMod:"+magicDmgMod +" / mr:"+mr);
			/*
			 * if (mr <= 100) { mrFloor = Math.floor((mr -
			 * _pc.getOriginalMagicHit()) / 2); } else if (mr >= 100) { mrFloor
			 * = Math.floor((mr - _pc.getOriginalMagicHit()) / 10); }
			 *
			 * if (mr <= 100) { mrCoefficient = 1 - 0.01 * mrFloor; } else if
			 * (mr >= 100) { mrCoefficient = 0.6 - 0.01 * mrFloor; } dmg *=
			 * mrCoefficient;
			 */

			if (this._calcType == this.PC_PC) {
				dmg -= (Random.nextInt(mr) + 1) * 1.5;
//				System.out.println("newDMG:"+dmg);
				if (dmg <= 0) {
					return 0;
				}
				dmg = Math.min(dmg, 8000);

			} else if (this._calcType == this.PC_NPC) {
				final int DmgReduce = this._targetNpc.getDmgReduceRate();

				if (DmgReduce >= 100) {
					dmg = 1;

				} else if (DmgReduce > 0) { // opqlo 怪物減傷倍率
					dmg = Math.max(dmg / DmgReduce, 1);

				} else if (this._targetNpc.getNpcTemplate().is_hard()) { // opqlo
																			// 硬皮怪
					dmg = Math.max(dmg / 4, 1);

				}
			}
		} else if (this._calcType == this.NPC_PC
				|| this._calcType == this.NPC_NPC) {
			if (mr <= 95) {
				final int rnd = Random.nextInt(100) + 1;
				if (mr >= rnd) {
					dmg /= 2;
				}
			} else {
				final int rnd = Random.nextInt(mr + 100) + 1; // opqlo
				if (mr >= rnd) {
					final int MrRange = Random.nextInt(mr) + 1; // opqlo
					if (mr >= 400) {
						dmg = Math.max((dmg - MrRange) / 4, 1);
					} else if (mr >= 300) {
						dmg = Math.max((dmg - MrRange) / 3, 1);
					} else if (mr >= 200) {
						dmg = Math.max((dmg - MrRange) / 2, 1);
					} else {
						dmg /= 2;
					}
				}
			}
		}

		return dmg;
	}

	// ●●●● ＮＰＣ へのファイアーウォールの魔法ダメージ算出 ●●●●
	public int calcNpcFireWallDamage() {
		int dmg = 0;
		final double attrDeffence = this.calcAttrResistance(L1Skills.ATTR_FIRE);
		final L1Skills l1skills = SkillsTable.getInstance().getTemplate(
				FIRE_WALL);
		dmg = (int) ((1.0 - attrDeffence) * l1skills.getDamageValue());

		if (L1AttackCancel.haveCancelSkill(this._targetNpc)) {
			dmg = 0;
		}

		final int DmgReduce = this._targetNpc.getDmgReduceRate();

		if (DmgReduce >= 100) {
			dmg = 1;

		} else if (DmgReduce > 0) { // opqlo 怪物減傷倍率
			dmg = Math.max(dmg / DmgReduce, 1);

		} else if (this._targetNpc.getNpcTemplate().is_hard()) { // opqlo 硬皮怪
			dmg = Math.max(dmg / 4, 1);

		}

		dmg = Math.max(dmg, 0);

		return dmg;
	}

	// ●●●● プレイヤー・ＮＰＣ から ＮＰＣ へのダメージ算出 ●●●●
	private int calcNpcMagicDamage(final int skillId) {
		int dmg = 0;
		if (skillId == FINAL_BURN) {
			if (this._calcType == this.PC_NPC) {
				dmg = this._pc.getCurrentMp();
			} else {
				dmg = this._npc.getCurrentMp();
			}
		} else {
			dmg = this.calcMagicDiceDamage(skillId);
			dmg = dmg * this.getLeverage() / 10;
		}

		if (L1AttackCancel.haveCancelSkill(this._targetNpc)) {
			return 0;
		}

		if (this._calcType == this.PC_NPC) { // プレイヤーからペット、サモンに攻撃
			boolean isNowWar = false;
			final int castleId = L1CastleLocation
					.getCastleIdByArea(this._targetNpc);
			if (castleId > 0) {
				isNowWar = ServerWarExecutor.get().isNowWar(castleId);
			}
			if (!isNowWar) {
				if (this._targetNpc instanceof L1PetInstance) {
					dmg /= 8;
				}
				if (this._targetNpc instanceof L1SummonInstance) {
					final L1SummonInstance summon = (L1SummonInstance) this._targetNpc;
					if (summon.isExsistMaster()) {
						dmg /= 8;
					}
				}
			}
		}

		/*
		 * if (_calcType == PC_NPC && _targetNpc != null) { final int npcId =
		 * _targetNpc.getNpcTemplate().get_npcId(); if (npcId >= 45912 && npcId
		 * <= 45915 // 恨みに満ちたソルジャー＆ソルジャーゴースト &&
		 * !_pc.hasSkillEffect(STATUS_HOLY_WATER)) { dmg = 0; }else if (npcId ==
		 * 45916 // 恨みに満ちたハメル将軍 &&
		 * !_pc.hasSkillEffect(STATUS_HOLY_MITHRIL_POWDER)) { dmg = 0; }else if
		 * (npcId == 45941 // 呪われた巫女サエル &&
		 * !_pc.hasSkillEffect(STATUS_HOLY_WATER_OF_EVA)) { dmg = 0; }else if
		 * (npcId == 45752 // バルログ(変身前) &&
		 * !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) { dmg = 0; }else if (npcId
		 * == 45753 // バルログ(変身後) && !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) {
		 * dmg = 0; }else if (npcId == 45675 // ヤヒ(変身前) &&
		 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { dmg = 0; }else if (npcId
		 * == 81082 // ヤヒ(変身後) && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { dmg
		 * = 0; }else if (npcId == 45625 // 混沌 &&
		 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { dmg = 0; }else if (npcId
		 * == 45674 // 死 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { dmg = 0;
		 * }else if (npcId == 45685 // 堕落 &&
		 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { dmg = 0; }else if (npcId
		 * >= 46068 && npcId <= 46091 // 欲望の洞窟側mob && _pc.getTempCharGfx() ==
		 * 6035) { dmg = 0; }else if (npcId >= 46092 && npcId <= 46106 //
		 * 影の神殿側mob && _pc.getTempCharGfx() == 6034) { dmg = 0; } }
		 */

		return dmg;
	}

	// ●●●● プレイヤー へのファイアーウォールの魔法ダメージ算出 ●●●●
	public int calcPcFireWallDamage() {
		int dmg = 0;
		final double attrDeffence = this.calcAttrResistance(L1Skills.ATTR_FIRE);
		final L1Skills l1skills = SkillsTable.getInstance().getTemplate(
				FIRE_WALL);
		dmg = (int) ((1.0 - attrDeffence) * l1skills.getDamageValue());
		if (L1AttackCancel.haveCancelSkill(this._targetPc)) {
			dmg = 0;
		}

		dmg = Math.max(dmg, 0);

		return dmg;
	}

	/* ■■■■■■■■■■■■■■ 魔法傷害算出 ■■■■■■■■■■■■■■ */

	// ●●●● プレイヤー・ＮＰＣ から プレイヤー への魔法ダメージ算出 ●●●●
	private int calcPcMagicDamage(final int skillId) {
		int dmg = 0;
		if (skillId == FINAL_BURN) {
			if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
				dmg = this._pc.getCurrentMp();
			} else {
				dmg = this._npc.getCurrentMp();
			}
		} else {
			if (this._calcType == this.PC_PC) {
				dmg = this.calcMagicDiceDamage(skillId);
			} else {
				dmg = this.calcMagicDiceDamage(skillId) * this.getLeverage()/ 10;
			}
		}
		// 心靈破壞消耗目標5點MP造成5倍精神傷害
		if (skillId == MIND_BREAK) {
			if (this._targetPc.getCurrentMp() >= 5) {
				this._targetPc.setCurrentMp(this._targetPc.getCurrentMp() - 5);
				if (this._calcType == this.PC_PC) {
					dmg += this._pc.getWis() * 5;
				} else if (this._calcType == this.NPC_PC) {
					dmg += this._npc.getWis() * 5;
				}
			}
		}

		dmg -= this._targetPc.getDamageReductionByArmor(); // 防具によるダメージ軽減

		// TODO 魔法娃娃DB化 &マジックドール効果 　ダメージリダクション
		/** 娃娃增加減傷opqlo改寫 **/
		dmg -= this._targetPc.getDollList().getDamageReduction();
		// TODO 魔法娃娃DB化

		if (this._targetPc.hasSkillEffect(COOKING_1_0_S) // 料理によるダメージ軽減
				|| this._targetPc.hasSkillEffect(COOKING_1_1_S)
				|| this._targetPc.hasSkillEffect(COOKING_1_2_S)
				|| this._targetPc.hasSkillEffect(COOKING_1_3_S)
				|| this._targetPc.hasSkillEffect(COOKING_1_4_S)
				|| this._targetPc.hasSkillEffect(COOKING_1_5_S)
				|| this._targetPc.hasSkillEffect(COOKING_1_6_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_0_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_1_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_2_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_3_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_4_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_5_S)
				|| this._targetPc.hasSkillEffect(COOKING_2_6_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_0_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_1_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_2_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_3_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_4_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_5_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_6_S)) {
			dmg -= 5;
		}
		if (this._targetPc.hasSkillEffect(COOKING_1_7_S) // デザートによるダメージ軽減
				|| this._targetPc.hasSkillEffect(COOKING_2_7_S)
				|| this._targetPc.hasSkillEffect(COOKING_3_7_S)) {
			dmg -= 5;
		}

		if (this._targetPc.hasSkillEffect(REDUCTION_ARMOR)) {

			dmg -= Math.max(this._targetPc.getLevel() - 50, 0) / 5 + 1;
		}
		if (this._targetPc.hasSkillEffect(DRAGON_SKIN)) {
			dmg -= 3;// TODO リニューアル後
		}

		if (this._targetPc.hasSkillEffect(PATIENCE)) {
			dmg -= 2;
		}

		if (this._calcType == this.NPC_PC) { // ペット、サモンからプレイヤーに攻撃
			boolean isNowWar = false;
			final int castleId = L1CastleLocation
					.getCastleIdByArea(this._targetPc);
			if (castleId > 0) {
				isNowWar = ServerWarExecutor.get().isNowWar(castleId);
			}
			if (!isNowWar) {
				if (this._npc instanceof L1PetInstance) {
					dmg /= 8;
				}
				if (this._npc instanceof L1SummonInstance) {
					final L1SummonInstance summon = (L1SummonInstance) this._npc;
					if (summon.isExsistMaster()) {
						dmg /= 8;
					}
				}
			}
		}

		if (L1AttackCancel.haveCancelSkill(this._targetPc)) {
			dmg = 0;
		} else if (this._targetPc.hasSkillEffect(IMMUNE_TO_HARM)) {
			dmg /= 2;
		}

		if (this._targetPc.hasSkillEffect(COUNTER_MIRROR)) {
			if (this._calcType == this.PC_PC) {
				if (Math.min(45, this._targetPc.getWis()) >= Random
						.nextInt(100) + 1) {
					final S_DoActionGFX GFX = new S_DoActionGFX(
							this._pc.getId(), ActionCodes.ACTION_Damage);
					this._pc.sendPackets(GFX);
					this._pc.broadcastPacketX8(GFX);
					final S_SkillSound skill = new S_SkillSound(
							this._targetPc.getId(), 4395);
					this._targetPc.sendPackets(skill);
					this._targetPc.broadcastPacketX8(skill);
					dmg = Math.min(dmg / 2, 10000);
					this._pc.receiveDamage(this._targetPc, dmg, false);
					dmg = 0;
					this._targetPc.killSkillEffectTimer(COUNTER_MIRROR);
				}
			} else if (this._calcType == this.NPC_PC) {
				final int npcId = this._npc.getNpcTemplate().get_npcId();
				if (npcId == 45681 || npcId == 45682 || npcId == 45683
						|| npcId == 45684) {

				} else if (!this._npc.getNpcTemplate().get_IsErase()) {
				} else {
					if (Math.min(45, this._targetPc.getWis()) >= Random
							.nextInt(100) + 1) {
						this._npc.broadcastPacketX8(new S_DoActionGFX(this._npc
								.getId(), ActionCodes.ACTION_Damage));
						final S_SkillSound skill = new S_SkillSound(
								this._targetPc.getId(), 4395);
						this._targetPc.sendPackets(skill);
						this._targetPc.broadcastPacketX8(skill);
						dmg = Math.min(dmg / 2, 10000);
						this._npc.receiveDamage(this._targetPc, dmg);
						this._targetPc.killSkillEffectTimer(COUNTER_MIRROR);
					}
				}
			}
		}

		return dmg;
	}

	private int calcProbability(final int skillId) {
		int attackLevel = 0;
		int defenseLevel = 0;
		int attackInt = 0; // 加入攻擊者智力
		try {
			if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
				attackLevel = this._pc.getLevel();
				attackInt = this._pc.getInt(); // 加入攻擊者智力
			} else {
				attackLevel = this._npc.getLevel();
				attackInt = this._npc.getInt(); // 加入攻擊者智力
			}

			if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
				defenseLevel = this._targetPc.getLevel();
			} else {
				defenseLevel = this._targetNpc.getLevel();
				if (skillId == RETURN_TO_NATURE) {
					if (this._targetNpc instanceof L1SummonInstance) {
						final L1SummonInstance summon = (L1SummonInstance) this._targetNpc;
						defenseLevel = summon.getMaster().getLevel();
					}
				}
			}

			int probability = 0;
			final L1Skills l1skills = SkillsTable.getInstance().getTemplate(
					skillId);

			if (skillId == ELEMENTAL_FALL_DOWN || skillId == RETURN_TO_NATURE
					|| skillId == ENTANGLE || skillId == WIND_SHACKLE
					|| skillId == POLLUTE_WATER || skillId == EARTH_BIND) {
				// 成功確率は 魔法固有係数 × LV差 + 基本確率
				probability = (int) (l1skills.getProbabilityDice() / 10D * (attackLevel - defenseLevel)) + 11;
				// 追加2倍智力影響(>> 1: 除) (<< 1: 乘)
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					probability += this._pc.getOriginalMagicHit() << 1;
					probability -= this.getTargetMr() / 80;
				}

			} else if (skillId == AREA_OF_SILENCE// 封印禁地
					|| skillId == STRIKER_GALE// 精準射擊
			) {
				probability = (int) (l1skills.getProbabilityDice() / 10D * (attackLevel - defenseLevel)) + 11;

				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					// 追加2倍智力影響(>> 1: 除) (<< 1: 乘)
					probability += this._pc.getOriginalMagicHit() << 1;
				}
			} else if (skillId == ERASE_MAGIC) {// 大地屏障
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					// 追加智力影響(>> 1: 除) (<< 1: 乘)
					if (attackLevel < defenseLevel) {// 攻擊者等級小於被攻擊者
						probability = 3 + (this._pc.getInt() >> 3);// /8

					} else if (attackLevel == defenseLevel) { // 攻擊者等級 等於 被攻擊者
						probability = 4 + (this._pc.getInt() >> 2);// /4

					} else {// 攻擊者等級大於被攻擊者
						probability = 5 + (this._pc.getInt() >> 1);// /2
					}
					// probability -= getTargetMr() / 40;
				}

			} else if (skillId == SHOCK_STUN) {// 衝擊之暈
				// TODO 成功確率基本確率 + LV差1每+-2%
				/*
				 * if (_calcType == PC_PC || _calcType == PC_NPC) { probability
				 * = l1skills.getProbabilityValue() + (attackLevel -
				 * defenseLevel)*2;
				 *
				 * }
				 */
				if (attackLevel < defenseLevel) {// 攻擊者等級小於被攻擊者
					probability = 35;// SRC 20

				} else if (attackLevel == defenseLevel) { // 攻擊者等級 等於 被攻擊者
					probability = 50;// SRC NO

				} else {// 攻擊者等級大於等於被攻擊者
					probability = 60;// SRC 80
				}
			} else if (skillId == PHANTASM) {// 幻想
				if (Random.nextInt(100) + 1 <= 30) {
					probability = 100;
				} else {
					probability = 0;
				}
			} else if (skillId == CONFUSION) { // 混亂
				if (Random.nextInt(100) + 1 <= Random.nextInt(10) + 20) {
					probability = 100;
				} else {
					probability = 0;
				}
			} else if (skillId == PANIC) {// 恐慌
				probability = l1skills.getProbabilityValue() + attackInt / 2;
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					// probability += 2 * _pc.getOriginalMagicHit();
					probability += this._pc.getOriginalMagicHit();
				}

			} else if (skillId == NPC_COUNTER_BARRIER) {// opqlo吉爾塔斯 反擊屏障
				probability += 80;

			} else if (skillId == COUNTER_BARRIER) {// 反擊屏障
				probability = 35;
				/*
				 * // 成功確率は 基本確率 + LV差1毎に+-1% probability =
				 * l1skills.getProbabilityValue() + attackLevel- defenseLevel;
				 * // オリジナルINTによる魔法命中 if (_calcType == PC_PC || _calcType ==
				 * PC_NPC) { //probability += 1 * _pc.getOriginalMagicHit();
				 * probability += (_pc.getOriginalMagicHit() << 1); }
				 */
			} else if (skillId == FREEZING_BREATH) {// TODO 寒冰噴吐
				// オリジナルINTによる魔法命中
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					probability += this._pc.getOriginalMagicHit();
				}
			} else if (skillId == GUARD_BRAKE || skillId == RESIST_FEAR
					|| skillId == HORROR_OF_DEATH) {// TODO ガードブレイク、フィアー、ホラーオブデス
				probability = 100;// TODO リニューアル後、必中となった

			} else if (skillId == SILENCE// 魔法封印
					|| skillId == WEAPON_BREAK// 壞物術
					|| skillId == SLOW) {// 緩速術
				final int dice3 = l1skills.getProbabilityDice();
				int diceCount3 = 0;

				if (this._pc != null && this._pc.isWizard()) {
					diceCount3 = this.getMagicBonus() + this.getMagicLevel()
							+ 1;

				} else {
					diceCount3 = this.getMagicBonus() + this.getMagicLevel()
							- 1;
				}

				diceCount3 = Math.max(diceCount3, 1);

				for (int i = 0; i < diceCount3; i++) {
					probability += Random.nextInt(dice3) + 1;
				}

				probability = (int) (probability * (this.getLeverage() / 10D));
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					// 智力(依職業)附加魔法命中
					probability += this._pc.getOriginalMagicHit() << 1;
				}
				// 扣除抗魔減免
				probability -= this.getTargetMr();

				// 等級差(被攻擊者 - 攻擊者) / 24
				final int levelR = Math.max(defenseLevel / 24, 1);

				probability /= levelR;

				/** ----------------其他魔法------------ **/
			} else {

				int diceCount = 0;
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					if (this._pc.isWizard()) {
						diceCount = this.getMagicBonus() + this.getMagicLevel()+ 1;
						/*
						 * } else if (_pc.isElf()) { diceCount = getMagicBonus()
						 * + getMagicLevel() - 1;
						 */
					} else {
						diceCount = this.getMagicBonus() + this.getMagicLevel()- 1;
					}
				}
				diceCount = Math.max(diceCount, 1);

				final int dice = l1skills.getProbabilityDice();
				for (int i = 0; i < diceCount; i++) {
					if (dice > 0) {
						probability += Random.nextInt(dice) + 1;
					}
				}
				probability = probability * (this.getLeverage() / 10);

				// オリジナルINTによる魔法命中
				if (this._calcType == this.PC_PC
						|| this._calcType == this.PC_NPC) {
					// probability += 2 * _pc.getOriginalMagicHit();
					// 智力(依職業)附加魔法命中 *2 (>> 1: 除) (<< 1: 乘)
					probability += this._pc.getOriginalMagicHit() << 1;
					probability -= this.getTargetMr();

				}

				/*
				 * if (probability >= getTargetMr()) { probability = 100; } else
				 * { probability = 0; }
				 */
				if (skillId == TAMING_MONSTER) {// 迷媚術
					double probabilityRevision = 1;
					if (this._targetNpc.getMaxHp() >> 2 > this._targetNpc
							.getCurrentHp()) {
						probabilityRevision = 1.3;
						// probabilityRevision = 0.7;

					} else if (this._targetNpc.getMaxHp() << 2 >> 2 > this._targetNpc
							.getCurrentHp()) {
						probabilityRevision = 1.2;
						// probabilityRevision = 0.4;

					} else if (this._targetNpc.getMaxHp() * 3 >> 2 > this._targetNpc.getCurrentHp()) {
						probabilityRevision = 1.1;
						// probabilityRevision = 0.2;
					}
					probability *= probabilityRevision;
				}
			}

			// 耐性 (>> 1: 除) (<< 1: 乘)

			if (this._calcType == this.PC_PC) {
				switch (skillId) {
				case EARTH_BIND:// 大地屏障 - 支撐耐性
					probability += this._pc.getSustainDice()
							- this._targetPc.getRegistSustain() >> 1;
					break;

				case SHOCK_STUN:// 衝擊之暈 - 昏迷耐性
				case BONE_BREAK:// 骷髏毀壞
					probability += this._pc.getStunDice()
							- this._targetPc.getRegistStun() >> 1;
					break;

				case CURSE_PARALYZE:// 木乃伊的詛咒 - 石化耐性
				case PHANTASM:// 幻想
					probability += this._pc.getStoneDice()
							- this._targetPc.getRegistStone() >> 1;
					break;

				case FOG_OF_SLEEPING:// 沉睡之霧 - 睡眠耐性
					probability += this._pc.getSleepDice()
							- this._targetPc.getRegistSleep() >> 1;
					break;

				case ICE_LANCE:// 冰矛圍籬 - 寒冰耐性
				case FREEZING_BREATH:// 寒冰噴吐
					probability += this._pc.getFreezeDice()
							- this._targetPc.getRegistFreeze() >> 1;
					break;

				case CURSE_BLIND:// 闇盲咒術 - 暗黑耐性
				case DARKNESS:// 黑闇之影
				case DARK_BLIND:// 暗黑盲咒
					probability += this._pc.getBlindDice()
							- this._targetPc.getRegistBlind() >> 1;
					break;
				}
			} else if (this._calcType == this.NPC_PC) {
				switch (skillId) {
				case EARTH_BIND:// 大地屏障 - 支撐耐性
					probability -= this._targetPc.getRegistSustain() >> 1;
					break;

				case SHOCK_STUN:// 衝擊之暈 - 昏迷耐性
				case BONE_BREAK:// 骷髏毀壞
					probability -= this._targetPc.getRegistStun() >> 1;
					break;

				case CURSE_PARALYZE:// 木乃伊的詛咒 - 石化耐性
				case PHANTASM:// 幻想
					probability -= this._targetPc.getRegistStone() >> 1;
					break;

				case FOG_OF_SLEEPING:// 沉睡之霧 - 睡眠耐性
					probability -= this._targetPc.getRegistSleep() >> 1;
					break;

				case ICE_LANCE:// 冰矛圍籬 - 寒冰耐性
				case FREEZING_BLIZZARD:// 冰雪颶風
				case FREEZING_BREATH:// 寒冰噴吐
					probability -= this._targetPc.getRegistFreeze() >> 1;
					break;

				case CURSE_BLIND:// 闇盲咒術 - 暗黑耐性
				case DARKNESS:// 黑闇之影
				case DARK_BLIND:// 暗黑盲咒
					probability -= this._targetPc.getRegistBlind() >> 1;
					break;
				}
			}

			/*
			 * // 異常狀態抗性 if(_calcType == PC_PC || _calcType == NPC_PC){
			 * switch(skillId){ case EARTH_BIND: probability -=
			 * _targetPc.getRegistSustain();break; case SHOCK_STUN: probability
			 * -= _targetPc.getRegistStun();break; case
			 * CURSE_PARALYZE:probability -= _targetPc.getRegistStone();break;
			 * case FOG_OF_SLEEPING:probability -=
			 * _targetPc.getRegistSleep();break; case ICE_LANCE: case
			 * FREEZING_BLIZZARD: case FREEZING_BREATH: probability -=
			 * _targetPc.getRegistBlind(); break; case CURSE_BLIND: case
			 * DARKNESS: case DARK_BLIND: probability -=
			 * _targetPc.getRegistBlind(); break; } }
			 */
			/*
			 * if (skillId == EARTH_BIND) { if (_calcType == PC_PC || _calcType
			 * == NPC_PC) { probability -= _targetPc.getRegistSustain(); } }
			 * else if (skillId == SHOCK_STUN) { if (_calcType == PC_PC ||
			 * _calcType == NPC_PC) { probability -= _targetPc.getRegistStun() +
			 * 10; } } else if (skillId == CURSE_PARALYZE) { if (_calcType ==
			 * PC_PC || _calcType == NPC_PC) { probability -=
			 * _targetPc.getRegistStone(); } } else if (skillId ==
			 * FOG_OF_SLEEPING) { if (_calcType == PC_PC || _calcType == NPC_PC)
			 * { probability -= _targetPc.getRegistSleep(); } } else if (skillId
			 * == ICE_LANCE || skillId == FREEZING_BLIZZARD || skillId ==
			 * FREEZING_BREATH) { if (_calcType == PC_PC || _calcType == NPC_PC)
			 * { probability -= _targetPc.getRegistBlind(); } } else if (skillId
			 * == CURSE_BLIND || skillId == DARKNESS || skillId == DARK_BLIND) {
			 * if (_calcType == PC_PC || _calcType == NPC_PC) { probability -=
			 * _targetPc.getRegistBlind(); } }
			 */

			return probability;
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}
		return 0;
	}

	/* ■■■■■■■■■■■■■■ 成功判定 ■■■■■■■■■■■■■ */
	// ●●●● 確率系魔法の成功判定 ●●●●
	// 計算方法
	// 攻撃方基準數：LV + ((MagicBonus * 3) * 魔法固有係数)
	// 防御方基準數：((LV / 2) + (MR * 3)) / 2
	// 攻撃成功率：攻撃方基準數 - 防御方基準數
	public boolean calcProbabilityMagic(final int skillId) {
		try {
			int probability = 0;
			boolean isSuccess = false;

			// TODO 怪物施展範圍負面魔法不會放到自己by9001183ex
			if (this._calcType == this.NPC_NPC) {
				if (this._targetNpc.getId() == this._npc.getId()) {
					return false;
				}
			}
			// TODO 怪物施展範圍負面魔法不會放到自己by9001183ex

			// 攻撃者がGM権限の場合100%成功by9001183ex
			if (this._pc != null && this._pc.isGm()) {
				return true;
			}

			/*
			 * if (_calcType == PC_NPC && _targetNpc != null) { final int npcId
			 * = _targetNpc.getNpcTemplate().get_npcId(); if (npcId >= 45912 &&
			 * npcId <= 45915 // 恨みに満ちたソルジャー＆ソルジャーゴースト &&
			 * !_pc.hasSkillEffect(STATUS_HOLY_WATER)) { return false; }else if
			 * (npcId == 45916 // 恨みに満ちたハメル将軍 &&
			 * !_pc.hasSkillEffect(STATUS_HOLY_MITHRIL_POWDER)) { return false;
			 * }else if (npcId == 45941 // 呪われた巫女サエル &&
			 * !_pc.hasSkillEffect(STATUS_HOLY_WATER_OF_EVA)) { return false;
			 * }else if (npcId == 45752 // バルログ(変身前) &&
			 * !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) { return false; }else
			 * if (npcId == 45753 // バルログ(変身後) &&
			 * !_pc.hasSkillEffect(STATUS_CURSE_BARLOG)) { return false; }else
			 * if (npcId == 45675 // ヤヒ(変身前) &&
			 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { return false; }else if
			 * (npcId == 81082 // ヤヒ(変身後) &&
			 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { return false; }else if
			 * (npcId == 45625 // 混沌 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE))
			 * { return false; }else if (npcId == 45674 // 死 &&
			 * !_pc.hasSkillEffect(STATUS_CURSE_YAHEE)) { return false; }else if
			 * (npcId == 45685 // 堕落 && !_pc.hasSkillEffect(STATUS_CURSE_YAHEE))
			 * { return false; }else if (npcId >= 46068 && npcId <= 46091 //
			 * 欲望の洞窟側mob && _pc.getTempCharGfx() == 6035) { return false; }else
			 * if (npcId >= 46092 && npcId <= 46106 // 影の神殿側mob &&
			 * _pc.getTempCharGfx() == 6034) { return false; } }
			 */
			if (this._calcType == this.PC_PC) {
				if (!this.checkZone(skillId)) {
					return false;
				}
			}
			if (skillId == CANCELLATION) {
				if (this._calcType == this.PC_PC && this._pc != null
						&& this._targetPc != null) {
					// 自分自身の場合は100%成功
					if (this._pc.getId() == this._targetPc.getId()) {
						return true;
					}
					// 同じクランの場合は100%成功
					if (this._pc.getClanid() > 0
							&& this._pc.getClanid() == this._targetPc
									.getClanid()) {
						return true;
					}
					// 同じパーティの場合は100%成功
					if (this._pc.isInParty()) {
						if (this._pc.getParty().isMember(this._targetPc)) {
							return true;
						}
					}
					// それ以外の場合、セーフティゾーン内では無効
					if (this._pc.getZoneType() == 1
							|| this._targetPc.getZoneType() == 1) {
						return false;
					}
				}
				// 対象がNPC、使用者がNPCの場合は100%成功
				if (this._calcType == this.PC_NPC
						|| this._calcType == this.NPC_PC
						|| this._calcType == this.NPC_NPC) {
					return true;
				}
			}

			// アースバインド中はWB、キャンセレーション以外無効
			if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
				if (this._targetPc.hasSkillEffect(EARTH_BIND)) {
					if (skillId != WEAPON_BREAK && skillId != CANCELLATION) {
						return false;
					}
				}
			} else {
				if (this._targetNpc.hasSkillEffect(EARTH_BIND)) {
					if (skillId != WEAPON_BREAK && skillId != CANCELLATION) {
						return false;
					}
				}
			}
			probability = this.calcProbability(skillId);
			// System.out.println(probability);
			probability = Math.min(probability, 70);// 最高成功率を90%とする。
			probability = Math.max(probability, 15);

			final int rnd = Random.nextInt(100) + 1;

			if (probability >= rnd) {
				isSuccess = true;
			} else {
				isSuccess = false;
			}

			// 確率系魔法メッセージ
			if (!Config.ALT_ATKMSG) {// TODO 設定GM是否顯示傷害訊息
				return isSuccess;
			}
			if (Config.ALT_ATKMSG) {// TODO 設定GM是否顯示傷害訊息
				if ((this._calcType == this.PC_PC || this._calcType == this.PC_NPC)
						&& !this._pc.isGm()) {
					return isSuccess;
				}
				if ((this._calcType == this.PC_PC || this._calcType == this.NPC_PC)
						&& !this._targetPc.isGm()) {
					return isSuccess;
				}
			}

			String msg0 = "";
			final String msg1 = "的";
			String msg2 = "";
			String msg3 = "";
			String msg4 = "";

			if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) { // アタッカーがＰＣの場合
				msg0 = this._pc.getName();
			} else if (this._calcType == this.NPC_PC) { // アタッカーがＮＰＣの場合
				msg0 = this._npc.getName();
			}

			msg2 = "準確率:" + probability + "%";
			if (this._calcType == this.NPC_PC || this._calcType == this.PC_PC) { // ターゲットがＰＣの場合
				msg4 = this._targetPc.getName();
			} else if (this._calcType == this.PC_NPC) { // ターゲットがＮＰＣの場合
				msg4 = this._targetNpc.getName();
			}
			if (isSuccess == true) {
				msg3 = "成功";
			} else {
				msg3 = "失敗";
			}

			if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) { // アタッカーがＰＣの場合
				this._pc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2,
						msg3, msg4)); // \f1%0が%4%1%3 %2
			}
			if (this._calcType == this.NPC_PC || this._calcType == this.PC_PC) { // ターゲットがＰＣの場合
				this._targetPc.sendPackets(new S_ServerMessage(166, msg0, msg1,
						msg2, msg3, msg4)); // \f1%0が%4%1%3 %2
			}

			return isSuccess;
		} catch (final Exception e) {
			_log.log(Level.SEVERE, e.getLocalizedMessage(), e);
		}
		return false;
	}

	private boolean checkZone(final int skillId) {
		if (this._pc != null && this._targetPc != null) {
			if (this._pc.getZoneType() == 1
					|| this._targetPc.getZoneType() == 1) { // セーフティーゾーン
				if (skillId == WEAPON_BREAK || skillId == SLOW
						|| skillId == CURSE_PARALYZE || skillId == MANA_DRAIN
						|| skillId == DARKNESS || skillId == WEAKNESS
						|| skillId == DISEASE || skillId == DECAY_POTION
						|| skillId == MASS_SLOW || skillId == ENTANGLE
						|| skillId == ERASE_MAGIC || skillId == EARTH_BIND
						|| skillId == AREA_OF_SILENCE
						|| skillId == WIND_SHACKLE || skillId == STRIKER_GALE
						|| skillId == SHOCK_STUN || skillId == FOG_OF_SLEEPING
						|| skillId == ICE_LANCE || skillId == FREEZING_BLIZZARD
						|| skillId == FREEZING_BREATH
						|| skillId == NPC_FREEZING_BREATH
						|| skillId == POLLUTE_WATER
						|| skillId == ELEMENTAL_FALL_DOWN
						|| skillId == RETURN_TO_NATURE) {
					return false;
				}
			}
		}
		return true;
	}

	public void commit(int damage, final int drainMana) {
		if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
			this.commitPc(damage, drainMana);
		} else if (this._calcType == this.PC_NPC
				|| this._calcType == this.NPC_NPC) {
			this.commitNpc(damage, drainMana);
		}

		// ダメージ値及び命中率確認用メッセージ
		// TODO 設定GM是否顯示傷害訊息
		if (!Config.ALT_ATKMSG) {
			return;
		}
		if (Config.ALT_ATKMSG) {
			if ((this._calcType == this.PC_PC || this._calcType == this.PC_NPC)
					&& !this._pc.isGm()) {
				return;
			}
			if ((this._calcType == this.PC_PC || this._calcType == this.NPC_PC)
					&& !this._targetPc.isGm()) {
				return;
			}
		}

		String msg0 = "";
		final String msg1 = "造成";
		String msg2 = "";
		String msg3 = "";
		String msg4 = "";

		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {// アタッカーがＰＣの場合
			msg0 = this._pc.getName();
		} else if (this._calcType == this.NPC_PC) { // アタッカーがＮＰＣの場合
			msg0 = this._npc.getName();
		}

		if (this._calcType == this.NPC_PC || this._calcType == this.PC_PC) { // ターゲットがＰＣの場合
			msg4 = this._targetPc.getName();
			msg2 = "剩餘" + this._targetPc.getCurrentHp();
		} else if (this._calcType == this.PC_NPC) { // ターゲットがＮＰＣの場合
			msg4 = this._targetNpc.getName();
			msg2 = "剩餘" + this._targetNpc.getCurrentHp();
		}

		msg3 = damage + "傷害";

		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) { // アタッカーがＰＣの場合
			this._pc.sendPackets(new S_ServerMessage(166, msg0, msg1, msg2,
					msg3, msg4)); // \f1%0が%4%1%3 %2
		}
		if (this._calcType == this.NPC_PC || this._calcType == this.PC_PC) { // ターゲットがＰＣの場合
			this._targetPc.sendPackets(new S_ServerMessage(166, msg0, msg1,
					msg2, msg3, msg4)); // \f1%0が%4%1%3 %2
		}
	}

	// TODO 設定GM是否顯示傷害訊息
	// ●●●● ＮＰＣに計算結果を反映 ●●●●
	private void commitNpc(final int damage, final int drainMana) {
		if (this._calcType == this.PC_NPC) {
			if (drainMana > 0) {
				final int drainValue = this._targetNpc.drainMana(drainMana);
				final int newMp = this._pc.getCurrentMp() + drainValue;
				this._pc.setCurrentMp(newMp);
			}
			this._targetNpc.ReceiveManaDamage(this._pc, drainMana);
			this._targetNpc.receiveDamage(this._pc, damage);
		} else if (this._calcType == this.NPC_NPC) {
			this._targetNpc.receiveDamage(this._npc, damage);
		}
	}

	// ●●●● プレイヤーに計算結果を反映 ●●●●
	private void commitPc(final int damage, final int drainMana) {
		if (this._calcType == this.PC_PC) {
			if (drainMana > 0 && this._targetPc.getCurrentMp() > 0) {

				final int newMp = this._pc.getCurrentMp()
						+ Math.min(drainMana, this._targetPc.getCurrentMp());
				this._pc.setCurrentMp(newMp);
			}
			this._targetPc.receiveManaDamage(this._pc, drainMana);
			this._targetPc.receiveDamage(this._pc, damage, true);
		} else if (this._calcType == this.NPC_PC) {
			this._targetPc.receiveDamage(this._npc, damage, true);
		}
	}

	private int getLawful() {
		int lawful = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
			lawful = this._pc.getLawful();
		} else if (this._calcType == this.NPC_PC
				|| this._calcType == this.NPC_NPC) {
			lawful = this._npc.getLawful();
		}
		return lawful;
	}

	private int getLeverage() {
		return this._leverage;
	}

	private int getMagicBonus() {
		int magicBonus = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
			magicBonus = this._pc.getMagicBonus();
		} else if (this._calcType == this.NPC_PC
				|| this._calcType == this.NPC_NPC) {
			magicBonus = this._npc.getMagicBonus();
		}
		return magicBonus;
	}

	/* ■■■■■■■■■■■■■■■ 計算結果反映 ■■■■■■■■■■■■■■■ */

	private int getMagicLevel() {
		int magicLevel = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.PC_NPC) {
			magicLevel = this._pc.getMagicLevel();
		} else if (this._calcType == this.NPC_PC
				|| this._calcType == this.NPC_NPC) {
			magicLevel = this._npc.getMagicLevel();
		}
		return magicLevel;
	}

	private int getTargetMr() {
		int mr = 0;
		if (this._calcType == this.PC_PC || this._calcType == this.NPC_PC) {
			mr = this._targetPc.getMr();
		} else {
			mr = this._targetNpc.getMr();
		}
		return mr;
	}

	public void setLeverage(final int i) {
		this._leverage = i;
	}
}
